public final class SMAA {

	final static float SMAA_THRESHOLD = 0.15f;
	final static int SMAA_MAX_SEARCH_STEPS = 4;
	final static int SMAA_MAX_SEARCH_STEPS_DIAG = 0;
	final static int SMAA_CORNER_ROUNDING = 100;

	final static float SMAA_DEPTH_THRESHOLD = (0.1f * SMAA_THRESHOLD);
	final static float SMAA_PREDICATION = 0;
	final static float SMAA_PREDICATION_THRESHOLD = 0.01f;
	final static float SMAA_PREDICATION_SCALE = 2.0f;
	final static float SMAA_PREDICATION_STRENGTH = 0.4f;
	final static float SMAA_REPROJECTION = 0;
	final static float SMAA_REPROJECTION_WEIGHT_SCALE = 30.0f;
	final static float SMAA_DIRECTX9_LINEAR_BLEND = 0;
	final static float SMAA_ONLY_COMPILE_PS = 0;
	final static float SMAA_AREATEX_MAX_DISTANCE = 16;
	final static float SMAA_AREATEX_MAX_DISTANCE_DIAG = 20;
	final static float[] SMAA_AREATEX_PIXEL_SIZE = new float[]{1.0f / 160.0f, 1.0f / 560.0f};
	final static float SMAA_AREATEX_SUBTEX_SIZE= (1.0f / 7.0f);
	
	final static int SMAA_HLSL_3;
	final static int SMAA_HLSL_4;
	final static int SMAA_HLSL_4_1;
	final static int SMAA_GLSL_3;
	final static int SMAA_GLSL_4;
	final static int SMAA_HLSL_3;
	final static int SMAA_HLSL_3;
	final static int SMAA_HLSL_3;

	
	
	//-----------------------------------------------------------------------------
	
	
	// Misc functions
	float abs(final float n) {
		return n < 0 ? -n : n;
	}
	
	float abs(final float[] k) {
		final int l = n.length;
		final float[] result = new float[l];
		float n;
		for (int i = 0; i < l; i++ ) {
			n = k[i];
			result[i] = n < 0 ? -n : n;
		}
		return result;
	}
	
	float step(final float a,final  float x) {
		return x < a ? 0 : 1;
	}
	
	float[] step(final float[] a,final  float[] x) {
		final int l = x.length;
		final float[] result = new float[l];
		for (int i = 0; i < l; i++ ) {
			result[i] = x[i] < a[i] ? 0 : 1;
		}
		return result;
	}
	

	/**
	 * Gathers current pixel, and the top-left neighbors.
	 */
	float[] SMAAGatherNeighbours(float[] texcoord,
	                            float[] offset[],
	                            SMAATexture2D tex) {
	    if (SMAA_HLSL_4_1 == 1 || SMAA_GLSL_4 == 1)
	    	return SMAAGather(tex, texcoord + SMAA_PIXEL_SIZE * float2(-0.5, -0.5)).grb;
	  
	    float P = SMAASample(tex, texcoord).r;
	    float Pleft = SMAASample(tex, offset[0].xy).r;
	    float Ptop  = SMAASample(tex, offset[0].zw).r;
	    return new float[]{P, Pleft, Ptop};
	 
	}

	/**
	 * Adjusts the threshold by means of predication.
	 */
	float[] SMAACalculatePredicatedThreshold(float[] texcoord,
	                                        float[] offset/*[3]*/,
	                                        SMAATexture2D colorTex,
	                                        SMAATexture2D predicationTex) {
	    float[] neighbours = SMAAGatherNeighbours(texcoord, offset, predicationTex);
	    float[] delta = abs(neighbours.xx - neighbours.yz);
	    float[] edges = step(SMAA_PREDICATION_THRESHOLD, delta);
	    return SMAA_PREDICATION_SCALE * SMAA_THRESHOLD * (1.0 - SMAA_PREDICATION_STRENGTH * edges);
	}

	//#if SMAA_ONLY_COMPILE_PS == 0
	//-----------------------------------------------------------------------------
	// Vertex Shaders

	/**
	 * Edge Detection Vertex Shader
	 */
	void SMAAEdgeDetectionVS(float[]position,
	                         out float[]svPosition,
	                         inout float[]texcoord,
	                         out float[]offset/*[3]*/) {
	    svPosition = position;

	    offset[0] = texcoord.xyxy + SMAA_PIXEL_SIZE.xyxy * float4(-1.0, 0.0, 0.0, -1.0);
	    offset[1] = texcoord.xyxy + SMAA_PIXEL_SIZE.xyxy * float4( 1.0, 0.0, 0.0,  1.0);
	    offset[2] = texcoord.xyxy + SMAA_PIXEL_SIZE.xyxy * float4(-2.0, 0.0, 0.0, -2.0);
	}

	/**
	 * Blend Weight Calculation Vertex Shader
	 */
	void SMAABlendingWeightCalculationVS(float[]position,
	                                     out float[]svPosition,
	                                     inout float[]texcoord,
	                                     out float[]pixcoord,
	                                     out float[]offset[3]) {
	    svPosition = position;

	    pixcoord = texcoord / SMAA_PIXEL_SIZE;

	    // We will use these offsets for the searches later on (see @PSEUDO_GATHER4):
	    offset[0] = texcoord.xyxy + SMAA_PIXEL_SIZE.xyxy * float4(-0.25, -0.125,  1.25, -0.125);
	    offset[1] = texcoord.xyxy + SMAA_PIXEL_SIZE.xyxy * float4(-0.125, -0.25, -0.125,  1.25);

	    // And these for the searches, they indicate the ends of the loops:
	    offset[2] = float4(offset[0].xz, offset[1].yw) + 
	                float4(-2.0, 2.0, -2.0, 2.0) *
	                SMAA_PIXEL_SIZE.xxyy * float(SMAA_MAX_SEARCH_STEPS);
	}

	/**
	 * Neighborhood Blending Vertex Shader
	 */
	void SMAANeighborhoodBlendingVS(float[]position,
	                                out float[]svPosition,
	                                inout float[]texcoord,
	                                out float[]offset[2]) {
	    svPosition = position;

	    offset[0] = texcoord.xyxy + SMAA_PIXEL_SIZE.xyxy * float4(-1.0, 0.0, 0.0, -1.0);
	    offset[1] = texcoord.xyxy + SMAA_PIXEL_SIZE.xyxy * float4( 1.0, 0.0, 0.0,  1.0);
	}

	/**
	 * Resolve Vertex Shader
	 */
	void SMAAResolveVS(float[]position,
	                   out float[]svPosition,
	                   inout float[]texcoord) {
	    svPosition = position;
	}

	/**
	 * Separate Vertex Shader
	 */
	void SMAASeparateVS(float[]position,
	                    out float[]svPosition,
	                    inout float[]texcoord) {
	    svPosition = position;
	}
	//#endif // SMAA_ONLY_COMPILE_PS == 0

	//#if SMAA_ONLY_COMPILE_VS == 0
	//-----------------------------------------------------------------------------
	// Edge Detection Pixel Shaders (First Pass)

	/**
	 * Luma Edge Detection
	 *
	 * IMPORTANT NOTICE: luma edge detection requires gamma-corrected colors, and
	 * thus 'colorTex' should be a non-sRGB texture.
	 */
	float[]SMAALumaEdgeDetectionPS(float[]texcoord,
	                               float[]offset[3],
	                               SMAATexture2D colorTex
	                               #if SMAA_PREDICATION == 1
	                               , SMAATexture2D predicationTex
	                               #endif
	                               ) {
	    // Calculate the threshold:
	    #if SMAA_PREDICATION == 1
	    float[]threshold = SMAACalculatePredicatedThreshold(texcoord, offset, colorTex, predicationTex);
	    #else
	    float[]threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD);
	    #endif

	    // Calculate lumas:
	    float[]weights = float3(0.2126, 0.7152, 0.0722);
	    float L = dot(SMAASample(colorTex, texcoord).rgb, weights);
	    float Lleft = dot(SMAASample(colorTex, offset[0].xy).rgb, weights);
	    float Ltop  = dot(SMAASample(colorTex, offset[0].zw).rgb, weights);

	    // We do the usual threshold:
	    float[]delta;
	    delta.xy = abs(L - float2(Lleft, Ltop));
	    float[]edges = step(threshold, delta.xy);

	    // Then discard if there is no edge:
	    if (dot(edges, float2(1.0, 1.0)) == 0.0)
	        discard;

	    // Calculate right and bottom deltas:
	    float Lright = dot(SMAASample(colorTex, offset[1].xy).rgb, weights);
	    float Lbottom  = dot(SMAASample(colorTex, offset[1].zw).rgb, weights);
	    delta.zw = abs(L - float2(Lright, Lbottom));

	    // Calculate the maximum delta in the direct neighborhood:
	    float[]maxDelta = max(delta.xy, delta.zw);
	    maxDelta = max(maxDelta.xx, maxDelta.yy);

	    // Calculate left-left and top-top deltas:
	    float Lleftleft = dot(SMAASample(colorTex, offset[2].xy).rgb, weights);
	    float Ltoptop = dot(SMAASample(colorTex, offset[2].zw).rgb, weights);
	    delta.zw = abs(float2(Lleft, Ltop) - float2(Lleftleft, Ltoptop));

	    // Calculate the final maximum delta:
	    maxDelta = max(maxDelta.xy, delta.zw);

	    /**
	     * Each edge with a delta in luma of less than 50% of the maximum luma
	     * surrounding this pixel is discarded. This allows to eliminate spurious
	     * crossing edges, and is based on the fact that, if there is too much
	     * contrast in a direction, that will hide contrast in the other
	     * neighbors.
	     * This is done after the discard intentionally as this situation doesn't
	     * happen too frequently (but it's important to do as it prevents some 
	     * edges from going undetected).
	     */
	    edges.xy *= step(0.5 * maxDelta, delta.xy);

	    return float4(edges, 0.0, 0.0);
	}

	/**
	 * Color Edge Detection
	 *
	 * IMPORTANT NOTICE: color edge detection requires gamma-corrected colors, and
	 * thus 'colorTex' should be a non-sRGB texture.
	 */
	float[]SMAAColorEdgeDetectionPS(float[]texcoord,
	                                float[]offset[3],
	                                SMAATexture2D colorTex
	                                #if SMAA_PREDICATION == 1
	                                , SMAATexture2D predicationTex
	                                #endif
	                                ) {
	    // Calculate the threshold:
	    #if SMAA_PREDICATION == 1
	    float[]threshold = SMAACalculatePredicatedThreshold(texcoord, offset, colorTex, predicationTex);
	    #else
	    float[]threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD);
	    #endif

	    // Calculate color deltas:
	    float[]delta;
	    float[]C = SMAASample(colorTex, texcoord).rgb;

	    float[]Cleft = SMAASample(colorTex, offset[0].xy).rgb;
	    float[]t = abs(C - Cleft);
	    delta.x = max(max(t.r, t.g), t.b);

	    float[]Ctop  = SMAASample(colorTex, offset[0].zw).rgb;
	    t = abs(C - Ctop);
	    delta.y = max(max(t.r, t.g), t.b);

	    // We do the usual threshold:
	    float[]edges = step(threshold, delta.xy);

	    // Then discard if there is no edge:
	    if (dot(edges, float2(1.0, 1.0)) == 0.0)
	        discard;

	    // Calculate right and bottom deltas:
	    float[]Cright = SMAASample(colorTex, offset[1].xy).rgb;
	    t = abs(C - Cright);
	    delta.z = max(max(t.r, t.g), t.b);

	    float[]Cbottom  = SMAASample(colorTex, offset[1].zw).rgb;
	    t = abs(C - Cbottom);
	    delta.w = max(max(t.r, t.g), t.b);

	    // Calculate the maximum delta in the direct neighborhood:
	    float maxDelta = max(max(max(delta.x, delta.y), delta.z), delta.w);

	    // Calculate left-left and top-top deltas:
	    float[]Cleftleft  = SMAASample(colorTex, offset[2].xy).rgb;
	    t = abs(C - Cleftleft);
	    delta.z = max(max(t.r, t.g), t.b);

	    float[]Ctoptop = SMAASample(colorTex, offset[2].zw).rgb;
	    t = abs(C - Ctoptop);
	    delta.w = max(max(t.r, t.g), t.b);

	    // Calculate the final maximum delta:
	    maxDelta = max(max(maxDelta, delta.z), delta.w);

	    // Local contrast adaptation in action:
	    edges.xy *= step(0.5 * maxDelta, delta.xy);

	    return float4(edges, 0.0, 0.0);
	}

	/**
	 * Depth Edge Detection
	 */
	float[]SMAADepthEdgeDetectionPS(float[]texcoord,
	                                float[]offset[3],
	                                SMAATexture2D depthTex) {
	    float[]neighbours = SMAAGatherNeighbours(texcoord, offset, depthTex);
	    float[]delta = abs(neighbours.xx - float2(neighbours.y, neighbours.z));
	    float[]edges = step(SMAA_DEPTH_THRESHOLD, delta);

	    if (dot(edges, float2(1.0, 1.0)) == 0.0)
	        discard;

	    return float4(edges, 0.0, 0.0);
	}

	//-----------------------------------------------------------------------------
	// Diagonal Search Functions

	#if SMAA_MAX_SEARCH_STEPS_DIAG > 0 || SMAA_FORCE_DIAGONAL_DETECTION == 1

	/**
	 * These functions allows to perform diagonal pattern searches.
	 */
	float SMAASearchDiag1(SMAATexture2D edgesTex, float[]texcoord, float[]dir, float c) {
	    texcoord += dir * SMAA_PIXEL_SIZE;
	    float[]e = float2(0.0, 0.0);
	    float i;
	    for (i = 0.0; i < float(SMAA_MAX_SEARCH_STEPS_DIAG); i++) {
	        e.rg = SMAASampleLevelZero(edgesTex, texcoord).rg;
	        SMAA_FLATTEN if (dot(e, float2(1.0, 1.0)) < 1.9) break;
	        texcoord += dir * SMAA_PIXEL_SIZE;
	    }
	    return i + float(e.g > 0.9) * c;
	}

	float SMAASearchDiag2(SMAATexture2D edgesTex, float[]texcoord, float[]dir, float c) {
	    texcoord += dir * SMAA_PIXEL_SIZE;
	    float[]e = float2(0.0, 0.0);
	    float i;
	    for (i = 0.0; i < float(SMAA_MAX_SEARCH_STEPS_DIAG); i++) {
	        e.g = SMAASampleLevelZero(edgesTex, texcoord).g;
	        e.r = SMAASampleLevelZeroOffset(edgesTex, texcoord, int2(1, 0)).r;
	        SMAA_FLATTEN if (dot(e, float2(1.0, 1.0)) < 1.9) break;
	        texcoord += dir * SMAA_PIXEL_SIZE;
	    }
	    return i + float(e.g > 0.9) * c;
	}

	/** 
	 * Similar to SMAAArea, this calculates the area corresponding to a certain
	 * diagonal distance and crossing edges 'e'.
	 */
	float[]SMAAAreaDiag(SMAATexture2D areaTex, float[]dist, float[]e, float offset) {
	    float[]texcoord = float(SMAA_AREATEX_MAX_DISTANCE_DIAG) * e + dist;

	    // We do a scale and bias for mapping to texel space:
	    texcoord = SMAA_AREATEX_PIXEL_SIZE * texcoord + (0.5 * SMAA_AREATEX_PIXEL_SIZE);

	    // Diagonal areas are on the second half of the texture:
	    texcoord.x += 0.5;

	    // Move to proper place, according to the subpixel offset:
	    texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;

	    // Do it!
	    #if SMAA_HLSL_3 == 1
	    return SMAASampleLevelZero(areaTex, texcoord).ra;
	    #else
	    return SMAASampleLevelZero(areaTex, texcoord).rg;
	    #endif
	}

	/**
	 * This searches for diagonal patterns and returns the corresponding weights.
	 */
	float[]SMAACalculateDiagWeights(SMAATexture2D edgesTex, SMAATexture2D areaTex, float[]texcoord, float[]e, int4 subsampleIndices) {
	    float[]weights = float2(0.0, 0.0);

	    float[]d;
	    d.x = e.r > 0.0? SMAASearchDiag1(edgesTex, texcoord, float2(-1.0,  1.0), 1.0) : 0.0;
	    d.y = SMAASearchDiag1(edgesTex, texcoord, float2(1.0, -1.0), 0.0);

	    SMAA_BRANCH
	    if (d.r + d.g > 2.0) { // d.r + d.g + 1 > 3
	        float[]coords = SMAAMad(float4(-d.r, d.r, d.g, -d.g), SMAA_PIXEL_SIZE.xyxy, texcoord.xyxy);

	        float[]c;
	        c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1,  0)).g;
	        c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0,  0)).r;
	        c.z = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1,  0)).g;
	        c.w = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, -1)).r;
	        float[]e = 2.0 * c.xz + c.yw;
	        float t = float(SMAA_MAX_SEARCH_STEPS_DIAG) - 1.0;
	        e *= step(d.rg, float2(t, t));

	        weights += SMAAAreaDiag(areaTex, d, e, float(subsampleIndices.z));
	    }

	    d.x = SMAASearchDiag2(edgesTex, texcoord, float2(-1.0, -1.0), 0.0);
	    float right = SMAASampleLevelZeroOffset(edgesTex, texcoord, int2(1, 0)).r;
	    d.y = right > 0.0? SMAASearchDiag2(edgesTex, texcoord, float2(1.0, 1.0), 1.0) : 0.0;

	    SMAA_BRANCH
	    if (d.r + d.g > 2.0) { // d.r + d.g + 1 > 3
	        float[]coords = SMAAMad(float4(-d.r, -d.r, d.g, d.g), SMAA_PIXEL_SIZE.xyxy, texcoord.xyxy);

	        float[]c;
	        c.x  = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1,  0)).g;
	        c.y  = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, -1)).r;
	        c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1,  0)).gr;
	        float[]e = 2.0 * c.xz + c.yw;
	        float t = float(SMAA_MAX_SEARCH_STEPS_DIAG) - 1.0;
	        e *= step(d.rg, float2(t, t));

	        weights += SMAAAreaDiag(areaTex, d, e, float(subsampleIndices.w)).gr;
	    }

	    return weights;
	}
	#endif

	//-----------------------------------------------------------------------------
	// Horizontal/Vertical Search Functions

	/**
	 * This allows to determine how much length should we add in the last step
	 * of the searches. It takes the bilinearly interpolated edge (see 
	 * @PSEUDO_GATHER4), and adds 0, 1 or 2, depending on which edges and
	 * crossing edges are active.
	 */
	float SMAASearchLength(SMAATexture2D searchTex, float[]e, float bias, float scale) {
	    // Not required if searchTex accesses are set to point:
	    // float[]SEARCH_TEX_PIXEL_SIZE = 1.0 / float2(66.0, 33.0);
	    // e = float2(bias, 0.0) + 0.5 * SEARCH_TEX_PIXEL_SIZE + 
	    //     e * float2(scale, 1.0) * float2(64.0, 32.0) * SEARCH_TEX_PIXEL_SIZE;
	    e.r = bias + e.r * scale;
	    return 255.0 * SMAASampleLevelZeroPoint(searchTex, e).r;
	}

	/**
	 * Horizontal/vertical search functions for the 2nd pass.
	 */
	float SMAASearchXLeft(SMAATexture2D edgesTex, SMAATexture2D searchTex, float[]texcoord, float end) {
	    /**
	     * @PSEUDO_GATHER4
	     * This texcoord has been offset by (-0.25, -0.125) in the vertex shader to
	     * sample between edge, thus fetching four edges in a row.
	     * Sampling with different offsets in each direction allows to disambiguate
	     * which edges are active from the four fetched ones.
	     */
	    float[]e = float2(0.0, 1.0);
	    while (texcoord.x > end && 
	           e.g > 0.8281 && // Is there some edge not activated?
	           e.r == 0.0) { // Or is there a crossing edge that breaks the line?
	        e = SMAASampleLevelZero(edgesTex, texcoord).rg;
	        texcoord -= float2(2.0, 0.0) * SMAA_PIXEL_SIZE;
	    }

	    // We correct the previous (-0.25, -0.125) offset we applied:
	    texcoord.x += 0.25 * SMAA_PIXEL_SIZE.x;

	    // The searches are bias by 1, so adjust the coords accordingly:
	    texcoord.x += SMAA_PIXEL_SIZE.x;

	    // Disambiguate the length added by the last step:
	    texcoord.x += 2.0 * SMAA_PIXEL_SIZE.x; // Undo last step
	    texcoord.x -= SMAA_PIXEL_SIZE.x * SMAASearchLength(searchTex, e, 0.0, 0.5);

	    return texcoord.x;
	}

	float SMAASearchXRight(SMAATexture2D edgesTex, SMAATexture2D searchTex, float[]texcoord, float end) {
	    float[]e = float2(0.0, 1.0);
	    while (texcoord.x < end && 
	           e.g > 0.8281 && // Is there some edge not activated?
	           e.r == 0.0) { // Or is there a crossing edge that breaks the line?
	        e = SMAASampleLevelZero(edgesTex, texcoord).rg;
	        texcoord += float2(2.0, 0.0) * SMAA_PIXEL_SIZE;
	    }

	    texcoord.x -= 0.25 * SMAA_PIXEL_SIZE.x;
	    texcoord.x -= SMAA_PIXEL_SIZE.x;
	    texcoord.x -= 2.0 * SMAA_PIXEL_SIZE.x;
	    texcoord.x += SMAA_PIXEL_SIZE.x * SMAASearchLength(searchTex, e, 0.5, 0.5);
	    return texcoord.x;
	}

	float SMAASearchYUp(SMAATexture2D edgesTex, SMAATexture2D searchTex, float[]texcoord, float end) {
	    float[]e = float2(1.0, 0.0);
	    while (texcoord.y > end && 
	           e.r > 0.8281 && // Is there some edge not activated?
	           e.g == 0.0) { // Or is there a crossing edge that breaks the line?
	        e = SMAASampleLevelZero(edgesTex, texcoord).rg;
	        texcoord -= float2(0.0, 2.0) * SMAA_PIXEL_SIZE;
	    }

	    texcoord.y += 0.25 * SMAA_PIXEL_SIZE.y;
	    texcoord.y += SMAA_PIXEL_SIZE.y;
	    texcoord.y += 2.0 * SMAA_PIXEL_SIZE.y;
	    texcoord.y -= SMAA_PIXEL_SIZE.y * SMAASearchLength(searchTex, e.gr, 0.0, 0.5);
	    return texcoord.y;
	}

	float SMAASearchYDown(SMAATexture2D edgesTex, SMAATexture2D searchTex, float[]texcoord, float end) {
	    float[]e = float2(1.0, 0.0);
	    while (texcoord.y < end && 
	           e.r > 0.8281 && // Is there some edge not activated?
	           e.g == 0.0) { // Or is there a crossing edge that breaks the line?
	        e = SMAASampleLevelZero(edgesTex, texcoord).rg;
	        texcoord += float2(0.0, 2.0) * SMAA_PIXEL_SIZE;
	    }
	    
	    texcoord.y -= 0.25 * SMAA_PIXEL_SIZE.y;
	    texcoord.y -= SMAA_PIXEL_SIZE.y;
	    texcoord.y -= 2.0 * SMAA_PIXEL_SIZE.y;
	    texcoord.y += SMAA_PIXEL_SIZE.y * SMAASearchLength(searchTex, e.gr, 0.5, 0.5);
	    return texcoord.y;
	}

	/** 
	 * Ok, we have the distance and both crossing edges. So, what are the areas
	 * at each side of current edge?
	 */
	float[]SMAAArea(SMAATexture2D areaTex, float[]dist, float e1, float e2, float offset) {
	    // Rounding prevents precision errors of bilinear filtering:
	    float[]texcoord = float(SMAA_AREATEX_MAX_DISTANCE) * round(4.0 * float2(e1, e2)) + dist;
	    
	    // We do a scale and bias for mapping to texel space:
	    texcoord = SMAA_AREATEX_PIXEL_SIZE * texcoord + (0.5 * SMAA_AREATEX_PIXEL_SIZE);

	    // Move to proper place, according to the subpixel offset:
	    texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;

	    // Do it!
	    #if SMAA_HLSL_3 == 1
	    return SMAASampleLevelZero(areaTex, texcoord).ra;
	    #else
	    return SMAASampleLevelZero(areaTex, texcoord).rg;
	    #endif
	}

	//-----------------------------------------------------------------------------
	// Corner Detection Functions

	void SMAADetectHorizontalCornerPattern(SMAATexture2D edgesTex, inout float[]weights, float[]texcoord, float[]d) {
	    #if SMAA_CORNER_ROUNDING < 100 || SMAA_FORCE_CORNER_DETECTION == 1
	    float[]coords = SMAAMad(float4(d.x, 0.0, d.y, 0.0),
	                            SMAA_PIXEL_SIZE.xyxy, texcoord.xyxy);
	    float[]e;
	    e.r = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(0.0,  1.0)).r;
	    bool left = abs(d.x) < abs(d.y);
	    e.g = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(0.0, -2.0)).r;
	    if (left) weights *= SMAASaturate(float(SMAA_CORNER_ROUNDING) / 100.0 + 1.0 - e);

	    e.r = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2(1.0,  1.0)).r;
	    e.g = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2(1.0, -2.0)).r;
	    if (!left) weights *= SMAASaturate(float(SMAA_CORNER_ROUNDING) / 100.0 + 1.0 - e);
	    #endif
	}

	void SMAADetectVerticalCornerPattern(SMAATexture2D edgesTex, inout float[]weights, float[]texcoord, float[]d) {
	    #if SMAA_CORNER_ROUNDING < 100 || SMAA_FORCE_CORNER_DETECTION == 1
	    float[]coords = SMAAMad(float4(0.0, d.x, 0.0, d.y),
	                            SMAA_PIXEL_SIZE.xyxy, texcoord.xyxy);
	    float[]e;
	    e.r = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 1.0, 0.0)).g;
	    bool left = abs(d.x) < abs(d.y);
	    e.g = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-2.0, 0.0)).g;
	    if (left) weights *= SMAASaturate(float(SMAA_CORNER_ROUNDING) / 100.0 + 1.0 - e);

	    e.r = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1.0, 1.0)).g;
	    e.g = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2(-2.0, 1.0)).g;
	    if (!left) weights *= SMAASaturate(float(SMAA_CORNER_ROUNDING) / 100.0 + 1.0 - e);
	    #endif
	}

	//-----------------------------------------------------------------------------
	// Blending Weight Calculation Pixel Shader (Second Pass)

	float[]SMAABlendingWeightCalculationPS(float[]texcoord,
	                                       float[]pixcoord,
	                                       float[]offset[3],
	                                       SMAATexture2D edgesTex, 
	                                       SMAATexture2D areaTex, 
	                                       SMAATexture2D searchTex,
	                                       int4 subsampleIndices) { // Just pass zero for SMAA 1x, see @SUBSAMPLE_INDICES.
	    float[]weights = float4(0.0, 0.0, 0.0, 0.0);

	    float[]e = SMAASample(edgesTex, texcoord).rg;

	    SMAA_BRANCH
	    if (e.g > 0.0) { // Edge at north
	        #if SMAA_MAX_SEARCH_STEPS_DIAG > 0 || SMAA_FORCE_DIAGONAL_DETECTION == 1
	        // Diagonals have both north and west edges, so searching for them in
	        // one of the boundaries is enough.
	        weights.rg = SMAACalculateDiagWeights(edgesTex, areaTex, texcoord, e, subsampleIndices);

	        // We give priority to diagonals, so if we find a diagonal we skip 
	        // horizontal/vertical processing.
	        SMAA_BRANCH
	        if (dot(weights.rg, float2(1.0, 1.0)) == 0.0) {
	        #endif

	        float[]d;

	        // Find the distance to the left:
	        float[]coords;
	        coords.x = SMAASearchXLeft(edgesTex, searchTex, offset[0].xy, offset[2].x);
	        coords.y = offset[1].y; // offset[1].y = texcoord.y - 0.25 * SMAA_PIXEL_SIZE.y (@CROSSING_OFFSET)
	        d.x = coords.x;

	        // Now fetch the left crossing edges, two at a time using bilinear
	        // filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to
	        // discern what value each edge has:
	        float e1 = SMAASampleLevelZero(edgesTex, coords).r;

	        // Find the distance to the right:
	        coords.x = SMAASearchXRight(edgesTex, searchTex, offset[0].zw, offset[2].y);
	        d.y = coords.x;

	        // We want the distances to be in pixel units (doing this here allow to
	        // better interleave arithmetic and memory accesses):
	        d = d / SMAA_PIXEL_SIZE.x - pixcoord.x;

	        // SMAAArea below needs a sqrt, as the areas texture is compressed 
	        // quadratically:
	        float[]sqrt_d = sqrt(abs(d));

	        // Fetch the right crossing edges:
	        float e2 = SMAASampleLevelZeroOffset(edgesTex, coords, int2(1, 0)).r;

	        // Ok, we know how this pattern looks like, now it is time for getting
	        // the actual area:
	        weights.rg = SMAAArea(areaTex, sqrt_d, e1, e2, float(subsampleIndices.y));

	        // Fix corners:
	        SMAADetectHorizontalCornerPattern(edgesTex, weights.rg, texcoord, d);

	        #if SMAA_MAX_SEARCH_STEPS_DIAG > 0 || SMAA_FORCE_DIAGONAL_DETECTION == 1
	        } else
	            e.r = 0.0; // Skip vertical processing.
	        #endif
	    }

	    SMAA_BRANCH
	    if (e.r > 0.0) { // Edge at west
	        float[]d;

	        // Find the distance to the top:
	        float[]coords;
	        coords.y = SMAASearchYUp(edgesTex, searchTex, offset[1].xy, offset[2].z);
	        coords.x = offset[0].x; // offset[1].x = texcoord.x - 0.25 * SMAA_PIXEL_SIZE.x;
	        d.x = coords.y;

	        // Fetch the top crossing edges:
	        float e1 = SMAASampleLevelZero(edgesTex, coords).g;

	        // Find the distance to the bottom:
	        coords.y = SMAASearchYDown(edgesTex, searchTex, offset[1].zw, offset[2].w);
	        d.y = coords.y;

	        // We want the distances to be in pixel units:
	        d = d / SMAA_PIXEL_SIZE.y - pixcoord.y;

	        // SMAAArea below needs a sqrt, as the areas texture is compressed 
	        // quadratically:
	        float[]sqrt_d = sqrt(abs(d));

	        // Fetch the bottom crossing edges:
	        float e2 = SMAASampleLevelZeroOffset(edgesTex, coords, int2(0, 1)).g;

	        // Get the area for this direction:
	        weights.ba = SMAAArea(areaTex, sqrt_d, e1, e2, float(subsampleIndices.x));

	        // Fix corners:
	        SMAADetectVerticalCornerPattern(edgesTex, weights.ba, texcoord, d);
	    }

	    return weights;
	}

	//-----------------------------------------------------------------------------
	// Neighborhood Blending Pixel Shader (Third Pass)

	float[]SMAANeighborhoodBlendingPS(float[]texcoord,
	                                  float[]offset[2],
	                                  SMAATexture2D colorTex,
	                                  SMAATexture2D blendTex) {
	    // Fetch the blending weights for current pixel:
	    float[]a;
	    a.xz = SMAASample(blendTex, texcoord).xz;
	    a.y = SMAASample(blendTex, offset[1].zw).g;
	    a.w = SMAASample(blendTex, offset[1].xy).a;

	    // Is there any blending weight with a value greater than 0.0?
	    SMAA_BRANCH
	    if (dot(a, float4(1.0, 1.0, 1.0, 1.0)) < 1e-5)
	        return SMAASampleLevelZero(colorTex, texcoord);
	    else {
	        float[]color = float4(0.0, 0.0, 0.0, 0.0);

	        // Up to 4 lines can be crossing a pixel (one through each edge). We
	        // favor blending by choosing the line with the maximum weight for each
	        // direction:
	        float[]offset;
	        offset.x = a.a > a.b? a.a : -a.b; // left vs. right 
	        offset.y = a.g > a.r? a.g : -a.r; // top vs. bottom

	        // Then we go in the direction that has the maximum weight:
	        if (abs(offset.x) > abs(offset.y)) // horizontal vs. vertical
	            offset.y = 0.0;
	        else
	            offset.x = 0.0;

	        #if SMAA_REPROJECTION == 1
	        // Fetch the opposite color and lerp by hand:
	        float[]C = SMAASampleLevelZero(colorTex, texcoord);
	        texcoord += sign(offset) * SMAA_PIXEL_SIZE;
	        float[]Cop = SMAASampleLevelZero(colorTex, texcoord);
	        float s = abs(offset.x) > abs(offset.y)? abs(offset.x) : abs(offset.y);

	        // Unpack the velocity values:
	        C.a *= C.a;
	        Cop.a *= Cop.a;

	        // Lerp the colors:
	        float[]Caa = SMAALerp(C, Cop, s);

	        // Unpack velocity and return the resulting value:
	        Caa.a = sqrt(Caa.a);
	        return Caa;
	        #elif SMAA_HLSL_4 == 1 || SMAA_DIRECTX9_LINEAR_BLEND == 0
	        // We exploit bilinear filtering to mix current pixel with the chosen
	        // neighbor:
	        texcoord += offset * SMAA_PIXEL_SIZE;
	        return SMAASampleLevelZero(colorTex, texcoord);
	        #else
	        // Fetch the opposite color and lerp by hand:
	        float[]C = SMAASampleLevelZero(colorTex, texcoord);
	        texcoord += sign(offset) * SMAA_PIXEL_SIZE;
	        float[]Cop = SMAASampleLevelZero(colorTex, texcoord);
	        float s = abs(offset.x) > abs(offset.y)? abs(offset.x) : abs(offset.y);
	        return SMAALerp(C, Cop, s);
	        #endif
	    }
	}

	//-----------------------------------------------------------------------------
	// Temporal Resolve Pixel Shader (Optional Pass)

	float[]SMAAResolvePS(float[]texcoord,
	                     SMAATexture2D colorTexCurr,
	                     SMAATexture2D colorTexPrev
	                     #if SMAA_REPROJECTION == 1
	                     , SMAATexture2D velocityTex
	                     #endif
	                     ) {
	    #if SMAA_REPROJECTION == 1
	    // Velocity is calculated from previous to current position, so we need to
	    // inverse it:
	    float[]velocity = -SMAASample(velocityTex, texcoord).rg;

	    // Fetch current pixel:
	    float[]current = SMAASample(colorTexCurr, texcoord);

	    // Reproject current coordinates and fetch previous pixel:
	    float[]previous = SMAASample(colorTexPrev, texcoord + velocity);

	    // Attenuate the previous pixel if the velocity is different:
	    float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0;
	    float weight = 0.5 * SMAASaturate(1.0 - (sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE));

	    // Blend the pixels according to the calculated weight:
	    return SMAALerp(current, previous, weight);
	    #else
	    // Just blend the pixels:
	    float[]current = SMAASample(colorTexCurr, texcoord);
	    float[]previous = SMAASample(colorTexPrev, texcoord);
	    return SMAALerp(current, previous, 0.5);
	    #endif
	}

	//-----------------------------------------------------------------------------
	// Separate Multisamples Pixel Shader (Optional Pass)

	#if SMAA_HLSL_4 == 1 || SMAA_HLSL_4_1 == 1
	void SMAASeparatePS(float[]position : SV_POSITION,
	                    float[]texcoord : TEXCOORD0,
	                    out float[]target0,
	                    out float[]target1,
	                    uniform SMAATexture2DMS2 colorTexMS) {
	    int2 pos = int2(position.xy);
	    target0 = SMAALoad(colorTexMS, pos, 0);
	    target1 = SMAALoad(colorTexMS, pos, 1);
	}
	#endif

}
